home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Applications / Eudora 1.3.1 / source / messact.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-16  |  27.1 KB  |  1,061 lines  |  [TEXT/MPS ]

  1. #define FILE_NUM 24
  2. /* Copyright (c) 1990-1992 by the University of Illinois Board of Trustees */
  3. #pragma load EUDORA_LOAD
  4. #pragma segment Message
  5.  
  6.     TEHandle MakeSubjectTXE(MessHandle messH);
  7.     void MessUpdate(MyWindowPtr win);
  8.     void MessSubjRect(MyWindowPtr win,Rect *r);
  9.     Boolean MessScroll(MyWindowPtr win,int h,int v);
  10.     void MessHelp(MyWindowPtr win,Point mouse);
  11.     short MyFSWrite(short refN,long *bytes,UPtr buffer);
  12.     void AddXlateTables(MyWindowPtr win,MenuHandle pmh);
  13.     void NewXlateTable(MyWindowPtr win,MenuHandle pmh,short item);
  14.     void MessZoomSize(MyWindowPtr win,Rect *zoom);
  15. #pragma segment Main
  16. /**********************************************************************
  17.  * MessClose - close a message window
  18.  **********************************************************************/
  19. Boolean MessClose(MyWindowPtr win)
  20. {
  21.     MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  22.     TOCType **tocH = (*messH)->tocH;
  23.     int sumNum = (*messH)->sumNum;
  24.     
  25.     if (Win2Body(win) && WinTEH(win) && Win2Body(win)!=WinTEH(win)) MessSwapTXE(messH);
  26.     if ((*messH)->stes[0]) STEDispose((*messH)->stes[0]);
  27.     if ((*messH)->stes[1]) STEDispose((*messH)->stes[1]);
  28.     LL_Remove(MessList,messH,(MessType **));
  29.     DisposHandle(messH);
  30.     (*tocH)->sums[sumNum].messH = nil;
  31.     return(True);
  32. }
  33. #pragma segment Message
  34.  
  35. /**********************************************************************
  36.  * MessMenu - handle menu choices for a message window
  37.  **********************************************************************/
  38. Boolean MessMenu(MyWindowPtr win,int menu,int item,short modifiers)
  39. {
  40.     Str63 scratch, which;
  41.     MessType **messH = (MessType **)((WindowPeek)win)->refCon;
  42.     TOCType **tocH = (*messH)->tocH;
  43.     int sumNum = (*messH)->sumNum;
  44.     Boolean result = False;
  45.     long dirId;
  46.     short function;
  47.     
  48.     switch (menu)
  49.     {
  50.         case FILE_MENU:
  51.             switch(item)
  52.             {
  53.                 case FILE_PRINT_ITEM:
  54.                 case FILE_PRINT_SELECT_ITEM:
  55.                     PrintOneMessage((*messH)->win,item==FILE_PRINT_SELECT_ITEM);
  56.                     result = True;
  57.                     break;
  58.                 case FILE_SAVE_AS_ITEM:
  59.                     SaveMessageAs(messH);
  60.                     result = True;
  61.                     break;
  62.             }
  63.             break;
  64.         case EDIT_MENU:
  65.             if (win->ro)
  66.                 switch (item)
  67.                 {
  68.                     case EDIT_COPY_ITEM:
  69.                         result = TESomething(win,item,0,modifiers);
  70.                         break;
  71.                 }
  72.             else
  73.             {
  74.                 result = TESomething(win,item,0,modifiers);
  75.                 if (item==EDIT_PASTE_ITEM || item==EDIT_QUOTE_ITEM)
  76.                 {
  77.                     Boolean foundOne=False;
  78.                     TEHandle teh = (*Win2MessH(win))->txes[SUBJ_HEAD-1];
  79.                     char *spot = *(*teh)->hText;
  80.                     char *end = spot + (*teh)->teLength;
  81.                     for (;spot<end;spot++)
  82.                         if (*spot=='\n') {*spot=' '; foundOne=True;}
  83.                     if (foundOne) {ResizeSTE(win->ste,nil);}
  84.                 }
  85.             }
  86.             break;
  87.         case MESSAGE_MENU:
  88.             switch (item)
  89.             {
  90.                 case MESSAGE_REPLY_ITEM:
  91.                     DoReplyMessage(win,modifiers,0,True);
  92.                     result = True;
  93.                     break;
  94.                 case MESSAGE_REDISTRIBUTE_ITEM:
  95.                     DoRedistributeMessage(win,0);
  96.                     result = True;
  97.                     break;
  98.                 case MESSAGE_FORWARD_ITEM:
  99.                     DoForwardMessage(win,0);
  100.                     result = True;
  101.                     break;
  102.                 case MESSAGE_SALVAGE_ITEM:
  103.                     DoSalvageMessage(win);
  104.                     result = True;
  105.                     break;
  106.                 case MESSAGE_DELETE_ITEM:
  107.                     if (CloseMyWindow(win))
  108.                     {
  109.                         DeleteMessage(tocH,sumNum);
  110.                         if ((*tocH)->win)
  111.                         {
  112.                             if (!PrefIsSet(PREF_NO_AUTO_OPEN) && sumNum<(*tocH)->count &&
  113.                                     (*tocH)->sums[sumNum].state==UNREAD)
  114.                             {
  115.                                 SelectBoxRange(tocH,sumNum,sumNum,False,-1,-1);
  116.                                 BoxOpen((*tocH)->win);
  117.                             }
  118.                             else
  119.                                 BoxSelectAfter((*tocH)->win,sumNum);
  120.                         }
  121.                     }
  122.                     result = True;
  123.                     break;
  124.             }
  125.             break;
  126.         case REPLY_TO_HIER_MENU:
  127.             DoReplyMessage(win,modifiers,item,True);
  128.             result = True;
  129.             break;
  130.         case FORWARD_TO_HIER_MENU:
  131.             DoForwardMessage(win,item);
  132.             result = True;
  133.             break;
  134.         case REDIST_TO_HIER_MENU:
  135.             DoRedistributeMessage(win,item);
  136.             result = True;
  137.             break;
  138.         case SPECIAL_MENU:
  139.             switch(item)
  140.             {
  141.                 case SPECIAL_MAKE_NICK_ITEM:
  142.                     MakeMessNick(win,modifiers);
  143.                     result = True;
  144.                     break;
  145.             }
  146.             break;
  147.         case PRIOR_MENU:
  148.             SetPriority(tocH,(*messH)->sumNum,Display2Prior(item));
  149.             result = True;
  150.             break;
  151.         default:
  152.             if (menu==TRANSFER_MENU)
  153.             {
  154.                 dirId = MyDirId;
  155.                 function = TRANSFER;
  156.             }
  157.             else if (menu<1||menu>=FIND_HIER_MENU) break;
  158.             else
  159.             {
  160.                 dirId = (*BoxMap)[menu % MAX_BOX_LEVELS];
  161.                 function = (menu-1)/MAX_BOX_LEVELS;
  162.             }
  163.             switch (function)
  164.             {
  165.                 case TRANSFER:
  166.                     PCopy(scratch,(*tocH)->name);
  167.                     if (GetTransferParams(menu,item,&dirId,which) &&
  168.                             (dirId!=(*tocH)->dirId || !EqualString(which,scratch,False,True)))
  169.                     {
  170.                         MoveMessage(tocH,sumNum,dirId,which,(modifiers&optionKey)!=0);
  171.                         if ((*tocH)->win && !(modifiers&optionKey))
  172.                         {
  173.                             BoxSelectAfter((*tocH)->win,sumNum);
  174.                             if (!PrefIsSet(PREF_NO_AUTO_OPEN) && (sumNum=BoxNextSelected(tocH,-1))>=0 && (*tocH)->sums[sumNum].state==UNREAD)
  175.                                 BoxOpen((*tocH)->win);
  176.                         }
  177.                     }
  178.                     result=True;
  179.                     break;
  180.                 default:
  181.                     break;
  182.             }
  183.     }
  184.     return(result);
  185.  
  186. /************************************************************************
  187.  * SaveMessageAs - save a message in text only form
  188.  ************************************************************************/
  189. void SaveMessageAs(MessHandle messH)
  190. {
  191.     long creator;
  192.     short vRefN, refN;
  193.     short err;
  194.     Str31 scratch,name;
  195.     
  196.     /*
  197.      * tickle stdfile
  198.      */
  199.     GetPref(scratch,PREF_CREATOR);
  200.     if (*scratch!=4) GetRString(scratch,TEXT_CREATOR);
  201.     BlockMove(scratch+1,&creator,4);
  202.     MakeMessFileName((*messH)->tocH,(*messH)->sumNum,name);
  203.     ExcludeHeaders = PrefIsSet(PREF_EXCLUDE_HEADERS);
  204.     Paragraphs = PrefIsSet(PREF_PARAGRAPHS);
  205.     if (err=SFPutOpen(name,&vRefN,creator,'TEXT',&refN,SaveAsFilter,SAVEAS_DLOG))
  206.         return;
  207.     
  208.     /*
  209.      * do it
  210.      */
  211.     err = SaveAsToOpenFile(refN,messH);
  212.     
  213.     /*
  214.      * close
  215.      */
  216.     (void) FSClose(refN);
  217.     
  218.     /*
  219.      * report error
  220.      */
  221.     if (err)
  222.     {
  223.         FileSystemError(COULDNT_SAVEAS,name,err);
  224.         FSDelete(name,vRefN);
  225.     }
  226. }
  227.  
  228. /************************************************************************
  229.  * SaveAsToOpenFile - continue the message saving process
  230.  ************************************************************************/
  231. short SaveAsToOpenFile(short refN,MessHandle messH)
  232. {
  233.     long bytes;
  234.     short err=0, itx;
  235.     UPtr where;
  236.     TEHandle teh=BodyOf(messH);
  237.     Str63 scratch;
  238.     
  239.     if (!Paragraphs)
  240.     {
  241.         if ((*messH)->txes[0])
  242.         {
  243.             for (itx=ExcludeHeaders?HEAD_LIMIT-1:0;!err && itx<HEAD_LIMIT;itx++)
  244.             {
  245.                 if (itx<HEAD_LIMIT-1)
  246.                 {
  247.                     GetRString(scratch,HEADER_STRN+itx+1);
  248.                     PCatC(scratch,' ');
  249.                     bytes = *scratch;
  250.                     (void) FSWrite(refN,&bytes,scratch+1);
  251.                 }
  252.                 bytes = (*(*messH)->txes[itx])->teLength;
  253.                 err = FSWrite(refN,&bytes,LDRef((*(*messH)->txes[itx])->hText));
  254.                 UL((*(*messH)->txes[itx])->hText);
  255.                 bytes = 1;
  256.                 if (!err) err = FSWrite(refN,&bytes,"\n");
  257.             }
  258.         }
  259.         else
  260.         {
  261.             where = LDRef((*teh)->hText);
  262.             bytes = (*teh)->teLength;
  263.             if (ExcludeHeaders)
  264.             {
  265.                 where += SumOf(messH)->bodyOffset - (*messH)->weeded;
  266.                 bytes -= SumOf(messH)->bodyOffset - (*messH)->weeded;
  267.                 while (bytes > 1 && *where == '\n') {where++;bytes--;}
  268.                 while (bytes>1&&where[bytes-1]==where[bytes-2]&&where[bytes-1]=='\n')
  269.                     bytes--;
  270.             }
  271.             err = FSWrite(refN,&bytes,where);
  272.             UL((*teh)->hText);
  273.         }
  274.     }
  275.     else
  276.     {
  277.         if ((*messH)->txes[0])
  278.         {
  279.             for (itx=ExcludeHeaders?HEAD_LIMIT-1:0;!err && itx<HEAD_LIMIT;itx++)
  280.             {
  281.                 if (itx<HEAD_LIMIT-1)
  282.                 {
  283.                     GetRString(scratch,HEADER_STRN+itx+1);
  284.                     PCatC(scratch,' ');
  285.                     bytes = *scratch;
  286.                     (void) FSWrite(refN,&bytes,scratch+1);
  287.                 }
  288.                 err = UnwrapSave(LDRef((*(*messH)->txes[itx])->hText),
  289.                                                  (*(*messH)->txes[itx])->teLength,0,refN);
  290.                 UL((*(*messH)->txes[itx])->hText);
  291.                 if (itx<HEAD_LIMIT-1 && !err)
  292.                 {
  293.                     bytes = 1;
  294.                     err = FSWrite(refN,&bytes,"\n");
  295.                 }
  296.             }
  297.         }
  298.         else
  299.         {
  300.             where = LDRef((*teh)->hText);
  301.             bytes = (*teh)->teLength;
  302.             if (ExcludeHeaders)
  303.             {
  304.                 where += SumOf(messH)->bodyOffset - (*messH)->weeded;
  305.                 bytes -= SumOf(messH)->bodyOffset - (*messH)->weeded;
  306.                 while (bytes > 1 && *where == '\n') {where++;bytes--;}
  307.                 while (bytes>1&&where[bytes-1]==where[bytes-2]&&where[bytes-1]=='\n')
  308.                     bytes--;
  309.             }
  310.             err = UnwrapSave(where,bytes,0,refN);
  311.             UL((*teh)->hText);
  312.         }
  313.     }
  314.     return(err);
  315. }
  316.  
  317. /************************************************************************
  318.  * UnwrapSave - save and unwrap a message
  319.  ************************************************************************/
  320. #define flushBChars() do {                                                                            \
  321.     if (bytes=bSpot-buffer)                                                                             \
  322.     {                                                                                                                         \
  323.          err = refN ? FSWrite(refN,&bytes,buffer) :                                 \
  324.          (WrapHandle ? PtrAndHand(buffer,WrapHandle,bytes) : noErr);\
  325.          if (err) goto done;                                                                                \
  326.          bSpot = buffer;                                                                                        \
  327.     }                                                                                                                         \
  328. } while (0)
  329. #define putBChar(theC) do {                                                                         \
  330.     *bSpot++ = theC;                                                                                            \
  331.     if (bSpot==bEnd) flushBChars();                                                             \
  332. } while (0)
  333. int UnwrapSave(UPtr text, short length, short offset, short refN)
  334. {
  335.     struct LineInfo
  336.     {
  337.             int length;
  338.             int indent;
  339.             int quote;
  340.             int needReturn;
  341.     };
  342.     struct LineInfo lines[2];
  343.     struct LineInfo *this, *last;
  344.     int flip;
  345.     int c;
  346.     UPtr tSpot;
  347.     int begin;
  348.     int spaces;
  349.     UPtr buffer = NuPtr(BUFFER_SIZE);
  350.     UPtr bSpot, bEnd;
  351.     int err=0;
  352.     long bytes;
  353.     Str31 s;
  354.     Byte quote=GetRString(s,QUOTE_PREFIX)[1];
  355.     short i;
  356.     
  357.     
  358.     if (!buffer) return(MemError());
  359.     bEnd = buffer+BUFFER_SIZE;
  360.     bSpot = buffer;
  361.  
  362.     WriteZero(lines,sizeof(lines));
  363.     this = lines;
  364.     last = lines+1;
  365.     flip=this->length=this->indent=this->needReturn=last->length=last->indent=0;
  366.     last->needReturn=begin=1;
  367.  
  368.     for (tSpot=text+offset;tSpot<text+length;tSpot++)
  369.     {
  370.         c = *tSpot;
  371.         if (c=='\n')
  372.         {
  373.             this->needReturn =    this->needReturn ||
  374.                                 this->indent>20 || this->length<40;
  375.             if (this->needReturn)
  376.             {
  377.                 if (this->length==0 && !last->needReturn)
  378.                 {
  379.                     putBChar('\n');
  380.                 }
  381.                 putBChar('\n');
  382.             }
  383.             else
  384.                 putBChar(' ');
  385.             last = this;
  386.             flip = 1-flip;
  387.             this = lines + flip;
  388.             this->length = this->quote = this->indent = this->needReturn = 0;
  389.             begin = 1;
  390.             spaces = 0;
  391.         }
  392.         else if (c==' ')
  393.         {
  394.             if (begin) this->indent++;
  395.             else spaces++;
  396.         }
  397.         else if (begin && c==quote)
  398.         {
  399.             this->quote++;
  400.         }
  401.         else
  402.         {
  403.             if (!begin)
  404.             {
  405.                 if (spaces>4 && SendWDS!=WrapSendWDS)
  406.                 {
  407.                     putBChar('\t');
  408.                     this->needReturn = 1;
  409.                 }
  410.                 else if (spaces)
  411.                 {
  412.                     putBChar(' ');
  413.                     this->length++;
  414.                 }
  415.             }
  416.             else if ((this->indent>last->indent || this->quote!=last->quote) &&
  417.                              !last->needReturn)
  418.             {
  419.                 putBChar('\n');
  420.                 for (i=0;i<this->quote;i++) putBChar(c);
  421.                 this->length += this->quote;
  422.             }
  423.             else if (this->quote && last->needReturn)
  424.             {
  425.                 for (i=0;i<this->quote;i++) putBChar(quote);
  426.                 this->length += this->quote;
  427.             }
  428.             begin = 0;
  429.             spaces = 0;
  430.             putBChar(c);
  431.             this->length++;
  432.         }
  433.     }
  434.     flushBChars();
  435. done:
  436.     DisposPtr(buffer);
  437.     return(err);
  438. }
  439.  
  440. /************************************************************************
  441.  * MessKey - handle a keydown in a message window
  442.  ************************************************************************/
  443. void MessKey(MyWindowPtr win, EventRecord *event)
  444. {
  445.     MessHandle messH = (MessHandle)win->qWindow.refCon;
  446.     TOCHandle tocH = (*messH)->tocH;
  447.     long uLetter = UnadornMessage(event)&charCodeMask;
  448.     
  449.     if (leftArrowChar<=uLetter && uLetter<=downArrowChar &&
  450.             ((event->modifiers&cmdKey)!=0 ?
  451.                 !PrefIsSet(PREF_NO_CMD_ARROW):PrefIsSet(PREF_PLAIN_ARROW)))
  452.     {
  453.         NextMess(tocH,messH,uLetter,event->modifiers);
  454.         return;
  455.     }
  456.     else if ((*messH)->txes[SUBJ_HEAD-1] &&
  457.                      (uLetter==tabChar || uLetter==enterChar))
  458.     {
  459.         MessSwapTXE(messH);
  460.         if (WinTEH(win) != BodyOf(messH)) TESetSelect(0,INFINITY,WinTEH(win));
  461.     }
  462.     else if (event->modifiers&cmdKey)
  463.     {
  464.         if ('1'<=uLetter && uLetter<='5')
  465.             SetPriority(tocH,(*messH)->sumNum,Display2Prior(uLetter-'0'));
  466.         else
  467.             SysBeep(20L);
  468.         return;
  469.     }
  470.     else if (win->ro && DirtyKey(event->message))
  471.         AlertStr(READ_ONLY_ALRT, Stop, nil);
  472.     else if (!win->ro && (uLetter==upArrowChar || uLetter==downArrowChar
  473.                      || uLetter==returnChar))
  474.         SysBeep(20L);
  475.     else
  476.     {
  477.         TEActivate((*(STEHandle)win->ste)->te);
  478.         TESomething(win,TEKEY,(short)(event->message & 0xff),event->modifiers);
  479.     }
  480. }
  481.  
  482. /************************************************************************
  483.  * NextMess - skip to the next message
  484.  ************************************************************************/
  485. void NextMess(TOCHandle tocH,MessHandle messH,short whichWay,long modifiers)
  486. {
  487.     MyWindowPtr win;
  488.     short next;
  489.     
  490.     switch (whichWay)
  491.     {
  492.         case upArrowChar:
  493.         case leftArrowChar:
  494.             next = (*messH)->sumNum-1;
  495.             break;
  496.         case downArrowChar:
  497.         case rightArrowChar:
  498.             next = (*messH)->sumNum+1;
  499.             break;
  500.         default:
  501.             return;
  502.     }
  503.     if (next!=(*messH)->sumNum)
  504.     {
  505.         if (!(modifiers & optionKey)) CloseMyWindow((*messH)->win);
  506.         if (next<0 || next>=(*tocH)->count) return;
  507.         if ((*tocH)->sums[next].messH)
  508.         {
  509.             win=(*(MessHandle)(*tocH)->sums[next].messH)->win;
  510.             ShowMyWindow(win);
  511.             SelectWindow(win);
  512.         }
  513.         else
  514.             (void) GetAMessage(tocH,next,nil,True);
  515.         SelectBoxRange(tocH,next,next,False,-1,-1);
  516.         BoxCenterSelection((*tocH)->win);
  517.     }
  518. }
  519.  
  520. /************************************************************************
  521.  * SaveAsFilter - look for hits on our two special items
  522.  ************************************************************************/
  523. pascal Boolean SaveAsFilter(DialogPtr dgPtr,EventRecord *event,short *item)
  524. {
  525.     Rect r;
  526.     short type;
  527.     Handle itemH;
  528.     Point mouse;
  529.     GrafPtr oldPort;
  530.     
  531.     GetPort(&oldPort);
  532.     SetPort(dgPtr);
  533.     if (event->what==nullEvent || event->what==updateEvt)
  534.     {
  535.         if (GetDItemState(dgPtr,SADL_PARAGRAPHS)!=Paragraphs)
  536.             SetDItemState(dgPtr,SADL_PARAGRAPHS,Paragraphs);
  537.         if (GetDItemState(dgPtr,SADL_EXCLUDE_HEADERS)==ExcludeHeaders)
  538.             SetDItemState(dgPtr,SADL_EXCLUDE_HEADERS,!ExcludeHeaders);
  539.     }
  540.     else if (event->what==mouseDown)
  541.     {
  542.         mouse = event->where;
  543.         GlobalToLocal(&mouse);
  544.         itemH = nil;
  545.         GetDItem(dgPtr,SADL_PARAGRAPHS,&type,&itemH,&r);
  546.         if (!itemH) goto done;
  547.         if (PtInRect(mouse,&r))
  548.         {
  549.             if (TrackControl(itemH,mouse,nil))
  550.             {
  551.                 Paragraphs = !GetDItemState(dgPtr,SADL_PARAGRAPHS);
  552.                 SetDItemState(dgPtr,SADL_PARAGRAPHS,Paragraphs);
  553.             }
  554.             goto done;
  555.         }
  556.         else
  557.         {
  558.             GetDItem(dgPtr,SADL_EXCLUDE_HEADERS,&type,&itemH,&r);
  559.             if (!itemH) goto done;
  560.             if (PtInRect(mouse,&r))
  561.             {
  562.                 if (TrackControl(itemH,mouse,nil))
  563.                 {
  564.                     ExcludeHeaders = GetDItemState(dgPtr,SADL_EXCLUDE_HEADERS);
  565.                     SetDItemState(dgPtr,SADL_EXCLUDE_HEADERS,!ExcludeHeaders);
  566.                 }
  567.                 goto done;
  568.             }
  569.         }
  570.     }
  571.     SetPort(oldPort);
  572.     return(DlgFilter(dgPtr,event,item));
  573.     
  574.     done:
  575.         SetPort(oldPort);
  576.         return(False);
  577. }
  578.  
  579. /************************************************************************
  580.  * MessClick - handle a click in the message window
  581.  ************************************************************************/
  582. void MessClick(MyWindowPtr win,EventRecord *event)
  583. {
  584.     Point pt = event->where;
  585.     Rect r,pr;
  586.     STEHandle ste=nil;
  587.     MessHandle messH = Win2MessH(win);
  588.     
  589.     GlobalToLocal(&pt);
  590.     r = (*(*messH)->stes[0])->encloseR;
  591.     if (GetPriorityRect(win,&pr) && PtInRect(pt,&pr))
  592.         PriorityMenu(win);
  593.     else if (PtInRect(pt,&r)) ste = (*messH)->stes[0];
  594.     else if ((*messH)->stes[1])
  595.     {
  596.         r = (*(*messH)->stes[1])->encloseR;
  597.         if (PtInRect(pt,&r)) ste = (*messH)->stes[1];
  598.     }
  599.     
  600.     if (ste)
  601.     {
  602.       if (win->ste != ste) MessSwapTXE(messH);
  603.         STEClick(win->ste,event);
  604.     }
  605.     else HandleControl(pt,win);
  606. }
  607.  
  608. /************************************************************************
  609.  * MessGonnaShow - get ready to show a message window
  610.  ************************************************************************/
  611. void MessGonnaShow(MyWindowPtr win)
  612. {
  613.     MessHandle messH = (MessHandle)win->qWindow.refCon;
  614.     short margin;
  615.     
  616.     win->didResize = MessDidResize;
  617.     win->key = MessKey;
  618.     win->update = MessUpdate;
  619.     win->help = MessHelp;
  620.     win->dontControl = True;
  621.     win->zoomSize = MessZoomSize;
  622.     if (PrefIsSet(PREF_ICON_BAR))
  623.     {
  624.         margin = 2*FontLead+FontDescent+2;
  625.         win->topMargin = win->contR.top = margin;
  626.         if (MakeSubjectTXE(messH))
  627.             win->click = MessClick;
  628.         else
  629.             win->topMargin = win->contR.top = 0;
  630.         ResizeSTE((*messH)->stes[0],&win->contR);
  631.     }
  632.     MyWindowDidResize(win,nil);
  633.     TEActivate(WinTEH(win));
  634. }
  635.  
  636. /************************************************************************
  637.  * MakeSubjectTXE - make a TERec for the subject
  638.  ************************************************************************/
  639. TEHandle MakeSubjectTXE(MessHandle messH)
  640. {
  641.     Str63 subject;
  642.     Rect view;
  643.     MyWindowPtr win=(*messH)->win;
  644.     STEHandle ste;
  645.     GrafPtr oldPort;
  646.     
  647.     GetPort(&oldPort);
  648.     SetPort(win);
  649.     
  650.     PCopy(subject,SumOf(messH)->subj);
  651.     
  652.     MessSubjRect(win,&view);
  653.  
  654.     if (ste=NewSTE(win,&view,False,False,True))
  655.     {
  656.         (*(*ste)->te)->crOnly = -1;
  657.         (*ste)->dontFrame = True;
  658.         STESetText(subject+1,*subject,ste);
  659.         (*messH)->txes[SUBJ_HEAD-1] = (*ste)->te;
  660.         (*messH)->stes[1] = ste;
  661.     }
  662.     
  663.     SetPort(oldPort);
  664.     return(ste ? (*ste)->te : nil);
  665. }
  666.  
  667. /************************************************************************
  668.  * MessUpdate - update a message window
  669.  ************************************************************************/
  670. void MessUpdate(MyWindowPtr win)
  671. {
  672.     Rect pr;
  673.     
  674.     if (win->qWindow.visible)
  675.     {
  676.         MessHandle messH = (MessHandle)win->qWindow.refCon;
  677.         TOCHandle tocH = (*messH)->tocH;
  678.         if (SumOf(messH)->state==UNREAD)
  679.             SetState(tocH,(*messH)->sumNum,READ);
  680.         if ((*messH)->txes[BODY])
  681.             STEUpdate((*messH)->stes[0]);
  682.         if ((*messH)->txes[SUBJ_HEAD-1])
  683.         {
  684.             Str31 label;
  685.             TEHandle teh = (*messH)->txes[SUBJ_HEAD-1];
  686.  
  687.             /*
  688.              * draw separators
  689.              */
  690.             MoveTo(0,win->topMargin); Line(INFINITY,0);
  691.             Move(0,-2); Line(-INFINITY,0);
  692.                         
  693.             /*
  694.              * draw priority
  695.              */
  696.             if (GetPriorityRect(win,&pr)) DrawPriority(&pr,SumOf(messH)->priority);
  697.                 
  698.             /*
  699.              * draw label
  700.              */
  701.             MoveTo(pr.right+FontWidth,(3*FontLead)/2);
  702.             GetRString(label,HEADER_STRN+SUBJ_HEAD);
  703.             DrawString(label);
  704.                         
  705.             /*
  706.              * and the text
  707.              */
  708.             STEUpdate((*messH)->stes[1]);
  709.         }
  710.     }
  711. }
  712.  
  713. /************************************************************************
  714.  * MessSwapTXE - switch txe's in a message window
  715.  ************************************************************************/
  716. void MessSwapTXE(MessHandle messH)
  717. {
  718.     MyWindowPtr win = (*messH)->win;
  719.     TEHandle subTeh = (*messH)->txes[SUBJ_HEAD-1];
  720.     TEHandle bodTeh = (*messH)->txes[BODY];
  721.     TEHandle newTeh = (WinTEH(win)==bodTeh) ? subTeh : bodTeh;
  722.  
  723.     TEDeactivate(WinTEH(win));
  724.     TEActivate(newTeh);
  725.     if (newTeh==bodTeh)
  726.   {
  727.         win->ste = (*messH)->stes[0];
  728.         win->ro = True;
  729.     }
  730.     else
  731.     {
  732.         win->ste = (*messH)->stes[1];
  733.         win->ro = False;
  734.     }
  735.     if (win->ro)
  736.     {
  737.         Str63 newSubj;
  738.         Str63 oldSubj;
  739.         Str255 title;
  740.         
  741.         win->showInsert = nil;
  742.         *newSubj = MIN(63,(*subTeh)->teLength);
  743.         BlockMove(*(*subTeh)->hText,newSubj+1,*newSubj);
  744.         PCopy(oldSubj,SumOf(messH)->subj);
  745.         if (!EqualString(oldSubj,newSubj,True,True))
  746.         {
  747.             PCopy(SumOf(messH)->subj,newSubj);
  748.             InvalSum((*messH)->tocH,(*messH)->sumNum);
  749.             CalcSumLengths((*messH)->tocH,(*messH)->sumNum);
  750.             (*(*messH)->tocH)->dirty = True;
  751.             MakeMessTitle(title,(*messH)->tocH,(*messH)->sumNum);
  752.             SetWTitle(win,title);
  753.         }
  754.     }
  755.     else win->showInsert = NOOP;
  756. }
  757.  
  758. /************************************************************************
  759.  * MessDidResize - resize a message window
  760.  ************************************************************************/
  761. void MessDidResize(MyWindowPtr win, Rect *oldContR)
  762. {
  763.     MessHandle messH = (MessHandle)win->qWindow.refCon;
  764.     Rect view;
  765.     TEHandle bodTeh = (*messH)->txes[BODY];
  766.     TEHandle subTeh = (*messH)->txes[SUBJ_HEAD-1];
  767.     
  768.     win->contR = ((GrafPtr)win)->portRect;
  769.     if (!subTeh)
  770.         TextDidResize(win,oldContR);
  771.     else
  772.     {
  773.         MessSubjRect(win,&view); 
  774.         ResizeSTE((*messH)->stes[1],&view);
  775.         win->contR.top = win->topMargin;
  776.         view = win->contR;
  777.         view.right+=1;
  778.         ResizeSTE((*messH)->stes[0],&view);
  779.     }
  780. }
  781.  
  782. /************************************************************************
  783.  * MessSubjRect - find the rect for the subject teh
  784.  ************************************************************************/
  785. void MessSubjRect(MyWindowPtr win,Rect *r)
  786. {
  787.     Str31 label;
  788.     MessHandle messH = Win2MessH(win);
  789.     short hi = win->vPitch+2*TE_VMARGIN+FontDescent;
  790.     Rect pr;
  791.     
  792.     GetPriorityRect(win,&pr);
  793.  
  794.     *r = win->contR;
  795.     r->left += pr.right + 
  796.         StringWidth(GetRString(label,HEADER_STRN+SUBJ_HEAD))+2*win->hPitch;
  797.     r->top = (3*win->vPitch)/2-FontAscent-TE_VMARGIN-1;
  798.     r->bottom = r->top+hi;
  799.     r->right -= GROW_SIZE;
  800. }
  801.  
  802. /************************************************************************
  803.  * MessCursor - set the cursor properly
  804.  ************************************************************************/
  805. void MessCursor(Point mouse)
  806. {
  807.     MyWindowPtr win=FrontWindow();
  808.     MessHandle messH = Win2MessH(win);
  809.     
  810.     if (CursorInRect(mouse,(*(*(*messH)->stes[0])->te)->viewRect,MouseRgn) ||
  811.             win->topMargin && CursorInRect(mouse,(*(*(*messH)->stes[1])->te)->viewRect,MouseRgn))
  812.         SetMyCursor(iBeamCursor);
  813.     else
  814.         SetMyCursor(arrowCursor);
  815. }
  816.  
  817.  
  818. /************************************************************************
  819.  * GetPriorityRect - where does the priority thing belong?
  820.  ************************************************************************/
  821. Boolean GetPriorityRect(MyWindowPtr win,Rect *pr)
  822. {
  823.     short v;
  824.     if (!win->topMargin)
  825.     {
  826.         SetRect(pr,0,0,0,0);
  827.         return(False);
  828.     }
  829.     else
  830.     {
  831.         v = (win->topMargin-16)/2;
  832.         SetRect(pr,v,v,v+16,v+16);
  833. #ifdef NEVER
  834.         pr->right += FontWidth*10;
  835. #endif
  836.         return(True);
  837.     }
  838. }
  839.  
  840. /************************************************************************
  841.  * DrawPriority - draw the message priority
  842.  ************************************************************************/
  843. void DrawPriority(Rect *pr,short p)
  844. {
  845.     SICNHand theSICN;
  846.     Rect ir = *pr;
  847.     ir.right = ir.left+16;
  848.     
  849.     p = Prior2Display(p);
  850.     if (theSICN = GetResource('SICN',PRIOR_SICN_BASE+p-1))
  851.         PlotSICN(&ir,theSICN,0);
  852.     if (((WindowPeek)qd.thePort)->windowKind!=CBOX_WIN &&((WindowPeek)qd.thePort)->windowKind!=MBOX_WIN)
  853.     {
  854. #ifdef NEVER
  855.         Str31 string;
  856.         MoveTo(ir.right+FontWidth/2,(3*FontLead)/2);
  857.         GetRString(string,PRIOR_STRN+p);
  858.         TextFont(FontID);
  859.         TextSize(FontSize);
  860.         DrawString(string);
  861. #endif
  862.         ir = *pr;
  863.         if (FontLead+FontDescent > 16) InsetRect(&ir,0,(16-FontDescent-FontLead)/2);
  864.         FrameRect(&ir);
  865.         MoveTo(ir.left+1,ir.bottom);
  866.         Line(ir.right-ir.left-1,0);
  867.         Line(0,ir.top-ir.bottom+1);
  868.     }
  869. }
  870.  
  871. /************************************************************************
  872.  * PriorityMenu - put up the priority menu, and set the priority
  873.  ************************************************************************/
  874. short PriorityMenu(MyWindowPtr win)
  875. {
  876.     MenuHandle pmh = GetMenu(PRIOR_MENU);
  877.     Rect pr;
  878.     MessHandle messH = Win2MessH(win);
  879.     short p = SumOf(messH)->priority;
  880.     long res;
  881.     short item;
  882.     
  883.     if (pmh)
  884.     {
  885.         AddXlateTables(win,pmh);
  886.         GetPriorityRect(win,&pr);
  887.         BitClr((Ptr)HiliteMode, pHiliteBit);
  888.         p = Prior2Display(p);
  889.         LocalToGlobal((Point *)&pr);
  890.         
  891.         InsertMenu(pmh,-1);
  892.         res = PopUpMenuSelect(pmh,pr.top,pr.left,p);
  893.         item = res&0xffff0000 ? res&0xff : 0;
  894.         if (item && item > XLATE_BAR_ITEM) NewXlateTable(win,pmh,item);
  895.         DeleteMenu(PRIOR_MENU);
  896.         
  897.         if (item && item<=5)
  898.         {
  899.             p = Display2Prior(item);
  900.             SetPriority((*messH)->tocH,(*messH)->sumNum,p);
  901.         }
  902.         else res = 0;
  903.         
  904.         DisposeMenu(pmh);
  905.     }
  906.     return(p);
  907. }
  908.  
  909.  
  910. /************************************************************************
  911.  * AddXlateTables - add named translate tables to the current menu
  912.  ************************************************************************/
  913. void AddXlateTables(MyWindowPtr win,MenuHandle pmh)
  914. {
  915.     Boolean added=False;
  916.     short i,n;
  917.     Handle h;
  918.     Str31 name;
  919.     long type;
  920.     short id;
  921.     short nowId = SumOf(Win2MessH(win))->tableId;
  922.     Boolean isOut = (*(*Win2MessH(win))->tocH)->which == OUT;
  923.     short defltId = GetRLong(PREF_STRN+(isOut ? PREF_OUT_XLATE : PREF_IN_XLATE));
  924.     
  925.     n = CountResources('taBL');
  926.     SetResLoad(False);
  927.     for (i=1;i<=n;i++)
  928.         if (h=GetIndResource('taBL',i))
  929.         {
  930.             GetResInfo(h,&id,&type,name);
  931.             ReleaseResource(h);
  932.             if (!ResError() && *name && ((id%2)==0)==isOut)
  933.             {
  934.                 if (!added)
  935.                 {
  936.                     added = True;
  937.                     AppendMenu(pmh,"\p-");
  938.                 }
  939.                 MyAppendMenu(pmh,name);
  940.                 if (id==defltId) SetItemStyle(pmh,CountMItems(pmh),outline);
  941.                 if (id==nowId || (id==defltId && nowId==DEFAULT_TABLE))
  942.                     SetItemMark(pmh,CountMItems(pmh),checkMark);
  943.             }
  944.         }
  945.     SetResLoad(True);
  946. }
  947.  
  948. /************************************************************************
  949.  * NewXlateTable - change the translate table for a window
  950.  ************************************************************************/
  951. void NewXlateTable(MyWindowPtr win,MenuHandle pmh,short item)
  952. {
  953.     Boolean makeDefault = (CurrentModifiers()&shiftKey)!=0;
  954.     short newId,mark=False;
  955.     long type;
  956.     Str31 name;
  957.     Handle h;
  958.     Boolean isOut = (*(*Win2MessH(win))->tocH)->which == OUT;
  959.     short id = SumOf(Win2MessH(win))->tableId;
  960.  
  961.     if (makeDefault) GetItemStyle(pmh,item,&mark);
  962.     else GetItemMark(pmh,item,&mark);
  963.     if (mark)
  964.         newId = NO_TABLE;
  965.     else
  966.     {
  967.         MyGetItem(pmh,item,name);
  968.         SetResLoad(False);
  969.         if (h=GetNamedResource('taBL',name))
  970.         {
  971.             GetResInfo(h,&newId,&type,name);
  972.             if (ResError()) newId = id;    /* do nothing */
  973.             ReleaseResource(h);
  974.         }
  975.         SetResLoad(True);
  976.     }
  977.     if (makeDefault)
  978.     {
  979.         NumToString(newId,name);
  980.         ChangeStrn(PREF_STRN,(isOut?PREF_OUT_XLATE:PREF_IN_XLATE),name);
  981.     }
  982.     else if (id!=newId)
  983.     {
  984.         SumOf(Win2MessH(win))->tableId = newId;
  985.         (*(*Win2MessH(win))->tocH)->dirty = True;
  986.         if (!isOut) ReopenMessage(win);
  987.     }
  988. }
  989.  
  990.  
  991. /************************************************************************
  992.  * MessZoomSize - figure the size of a message window
  993.  ************************************************************************/
  994. void MessZoomSize(MyWindowPtr win,Rect *zoom)
  995. {
  996.     short hi,wi;
  997.     short oldRight;
  998.     TEHandle teh = Win2Body(win);
  999.     
  1000.     if (!(wi=GetRLong(PREF_STRN+PREF_MWIDTH))) wi=GetRLong(DEF_MWIDTH);
  1001.     wi *= win->hPitch; wi += GROW_SIZE+2*TE_HMARGIN;
  1002.     zoom->right = zoom->left + MIN(zoom->right-zoom->left,wi);
  1003.  
  1004.     oldRight = (*teh)->destRect.right;
  1005.     (*teh)->destRect.right = (*teh)->destRect.left + zoom->right-zoom->left-GROW_SIZE-2*TE_HMARGIN;
  1006.     TECalText(teh);
  1007.     hi = CountTeLines(teh)*win->vPitch + 2*TE_VMARGIN + win->topMargin;
  1008.     zoom->bottom = zoom->top + MIN(zoom->bottom-zoom->top,hi);
  1009.     (*teh)->destRect.right = oldRight;
  1010. }
  1011.  
  1012. /************************************************************************
  1013.  * MessApp1 - scroll the message, not the subject
  1014.  ************************************************************************/
  1015. Boolean MessApp1(MyWindowPtr win,EventRecord *event)
  1016. {
  1017.     STEApp1((*Win2MessH(win))->stes[0],event);
  1018.     return(True);
  1019. }
  1020.  
  1021. #pragma segment Balloon
  1022. /************************************************************************
  1023.  * MessHelp - help for the message window
  1024.  ************************************************************************/
  1025. void MessHelp(MyWindowPtr win,Point mouse)
  1026. {
  1027.     Rect subRect,bodRect,priorRect;
  1028.  
  1029.     bodRect = (*Win2Body(win))->viewRect;
  1030.     
  1031.     if (PtInRect(mouse,&bodRect))
  1032.         HelpRect(&bodRect,MESS_HELP,90);
  1033.     else if (win->topMargin)
  1034.     {
  1035.         subRect = (*(*Win2MessH(win))->txes[SUBJ_HEAD-1])->viewRect;
  1036.         GetPriorityRect(win,&priorRect);
  1037.         
  1038.         if (PtInRect(mouse,&subRect))
  1039.             HelpRect(&subRect,SUB_EDIT_HELP,90);
  1040.         else if (PtInRect(mouse,&priorRect))
  1041.             PriorMenuHelp(win,&priorRect);
  1042.     }
  1043. }
  1044.  
  1045. /************************************************************************
  1046.  * PriorMenuHelp - help for the priority menu
  1047.  ************************************************************************/
  1048. void PriorMenuHelp(MyWindowPtr win,Rect *priorRect)
  1049. {
  1050.     Str255 s1,s2;
  1051.     short p = Prior2Display((SumOf(Win2MessH(win)))->priority);
  1052.     if (!HMIsBalloon())
  1053.     {
  1054.         GetRString(s1,PRIOR_MENU_HELP);
  1055.         GetRString(s2,PRIOR_STRN+5+p);
  1056.         PCat(s1,s2);
  1057.         HelpRectString(priorRect,s1,90);
  1058.     }
  1059. }
  1060.